package simple.form.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.log4j.Logger;
import simple.form.controller.annotation.Controller;
import simple.form.controller.annotation.RequestMapping;
import simple.form.core.ParameterBeanManager;
import simple.form.core.RequestBean;
import simple.form.core.annotation.AutoWrite;
import simple.form.core.annotation.Component;
import simple.form.dao.Table;
import simple.form.dao.annotation.Entity;
import simple.form.db.DefaultDataSource;
import simple.form.utils.ClassUtil;
import simple.form.utils.FileUtil;
import simple.form.utils.SafeConvertUtil;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Administrator on 2017/2/20.
 */
@WebListener
public class SysInit implements ServletContextListener {
    public static Logger log4j = Logger.getLogger(SysInit.class);
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {


        log4j.info("开始初始化系统");
        //测试用start//
        //加载配置文件//
        JSONObject config = JSON.parseObject(FileUtil.readAllText(Thread.currentThread().getContextClassLoader().getResource("config.json").getPath()));
        //Controller包路径
        SysContent.controllerPackageName = SafeConvertUtil.toString(config.get("controllerPackageName"));
        //service包路径
        SysContent.servicePackageName = SafeConvertUtil.toString(config.get("servicePackageName"));
        //form表单bean包路径
        SysContent.formBeanPackageName = SafeConvertUtil.toString(config.get("formBeanPackageName"));
        //entity包路径
        SysContent.ormPackageName =SafeConvertUtil.toString(config.get("ormPackageName"));
        //DAO包路径
        SysContent.daoPackageName = SafeConvertUtil.toString(config.get("daoPackageName"));

        //数据源初始化//
        SysContent.dataSource = new DefaultDataSource(JSON.parseObject(FileUtil.readAllText(Thread.currentThread().getContextClassLoader().getResource("db.json").getPath())));
        //测试用end//
        ParameterBeanManager.getInstance().init(SysContent.formBeanPackageName);

        List<Class<?>> controllers = ClassUtil.getClasses(SysContent.controllerPackageName);
        List<Class<?>> services = ClassUtil.getClasses(SysContent.servicePackageName);
        List<Class<?>> daos = ClassUtil.getClasses(SysContent.daoPackageName);
        List<Class<?>> ormBeans = ClassUtil.getClasses(SysContent.ormPackageName);

        Method[] methods =null;
        RequestMapping requestMapping = null;
        String controllerName;
        String requestUrl;
        Class cacheKey;
        boolean isController = false;
        for(Class clas:controllers){
            if(clas.isAnnotationPresent(Controller.class)){
                isController = true;
            }else{
                isController = false;
                continue;
            }
            controllerName = SafeConvertUtil.toString(clas.getName());
            methods = clas.getMethods();
            for(Method method:methods){
                if(method.isAnnotationPresent(RequestMapping.class)){
                    requestMapping = method.getAnnotation(RequestMapping.class);
                    requestUrl = SafeConvertUtil.toString(requestMapping.url());
                    cacheKey = requestMapping.cacheKey();
                    if(!requestUrl.isEmpty()){
                        if(!SysContent.requestMappingController.containsKey(requestUrl)){
                            SysContent.requestMappingController.put(requestUrl,controllerName);
                        }
                        if(!SysContent.requestMappingMethod.containsKey(requestUrl)){
                            SysContent.requestMappingMethod.put(requestUrl,method);
                        }
                        if(!SysContent.requestMappingCacheKey.containsKey(requestUrl)){
                            //默认key就不保存url的映射了
                            if(!cacheKey.getName().equals(RequestBean.class.getName())){
                                SysContent.requestMappingCacheKey.put(requestUrl,cacheKey);
                            }
                        }

                    }
                }

            }
            if(isController){
                try {
                    SysContent.controller.put(controllerName, Class.forName(controllerName).newInstance());
                } catch (InstantiationException e) {
                    log4j.info("初始化controller失败",e);
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    log4j.info("初始化controller失败",e);
                    e.printStackTrace();
                } catch (ClassNotFoundException e) {
                    log4j.info("初始化controller失败",e);
                }
            }


        }

        initDao(daos);
        initService(services);
        initController(controllers);
        initORM(ormBeans);
        log4j.info("初始化系统成功");


    }

    /**
     * 初始化dao
     * @param daos
     */
    private void initDao(List<Class<?>> daos) {
        String daoName;
        for(Class clas:daos){
            if(clas.isAnnotationPresent(Component.class)){
                daoName = SafeConvertUtil.toString(clas.getName());
                daoName = daoName.substring(daoName.lastIndexOf(".")+1);
                try {
                    SysContent.daos.put(daoName,clas.newInstance());
                } catch (InstantiationException e) {
                    log4j.info("初始化dao失败", e);
                } catch (IllegalAccessException e) {
                    log4j.info("初始化dao失败", e);
                }
            }
        }
    }

    /**
     * 初始化bean对应的表映射
     * @param ormBeans
     */
    private void initORM(List<Class<?>> ormBeans) {
        boolean isTable =false;
        String beanName;
        String tableName;
        String keyName;
        Entity entity;
        Table table;
        String fieldName;
        Class fieldType;
        for(Class clas:ormBeans){
            if(clas.isAnnotationPresent(Entity.class)){
                isTable = true;
                entity = (Entity) clas.getAnnotation(Entity.class);
                tableName = SafeConvertUtil.toString(entity.name());
                keyName = SafeConvertUtil.toString(entity.keyName());
                beanName = SafeConvertUtil.toString(clas.getName());
                table = new Table(keyName,tableName);
                Field[] fields = clas.getDeclaredFields();
                for(Field field:fields){
                    fieldName = field.getName();
                    fieldType = field.getType();
                    table.addField(fieldName,fieldType);
                }
                SysContent.beansMappingTables.put(beanName,table);
            }else{
                isTable = false;
                continue;
            }
        }

    }

    /**
     * 初始化Service
     * @param services
     */
    private void initService(List<Class<?>> services) {
        String serviceName = null;
        String fieldTypeName;
        Object service;
        Object dao =null;
        Method setMethod =null;
        List<Object>  serviceDaos = new ArrayList<>();
        for(Class clas:services){
            if(clas.isAnnotationPresent(Component.class)){
                serviceName = SafeConvertUtil.toString(clas.getName());
                serviceName = serviceName.substring(serviceName.lastIndexOf(".")+1);
                try {
                    Field[] fields = clas.getDeclaredFields();
                    service = clas.newInstance();
                    SysContent.services.put(serviceName,service);

                    for(Field field:fields){
                        if(field.isAnnotationPresent(AutoWrite.class)){
                            Class fieldclass = field.getType();
                            try {
                                fieldTypeName = fieldclass.getName();
                                fieldTypeName = fieldTypeName.substring(fieldTypeName.lastIndexOf(".")+1);
                                dao = SysContent.daos.get(fieldTypeName);
                                serviceDaos.add(dao);
                                setMethod = clas.getMethod(String.format("set%s", fieldTypeName), fieldclass);
                            } catch (NoSuchMethodException e) {
                                log4j.info("初始化service dao失败",e);
                            }

                            if(service!=null){
                                try {
                                    setMethod.invoke(service,dao);
                                } catch (IllegalAccessException e) {
                                    log4j.info("初始化service dao失败",e);
                                } catch (InvocationTargetException e) {
                                    log4j.info("初始化service dao失败",e);
                                }
                            }

                        }
                    }

                } catch (InstantiationException e) {
                    log4j.info("初始化dao失败", e);
                } catch (IllegalAccessException e) {
                    log4j.info("初始化dao失败", e);
                }
            }
            SysContent.servicesDao.put(serviceName,serviceDaos);

        }

    }

    /***
     * 初始化controller
     * @param controllers
     */
    private void initController(List<Class<?>> controllers) {
        String controllerName;
        String fieldTypeName;
        Object controller;
        Object service = null;
        Method setMethod = null;
        List<Object> controllerServices;
        for(Class clas:controllers){
            controllerServices = new ArrayList<>();
            controllerName = clas.getName();
            Field[] fields = clas.getDeclaredFields();
            for(Field field:fields){
                if(field.isAnnotationPresent(AutoWrite.class)){
                    Class fieldclass = field.getType();
                    try {
                        fieldTypeName = fieldclass.getName();
                        fieldTypeName = fieldTypeName.substring(fieldTypeName.lastIndexOf(".")+1);
                        service = SysContent.services.get(fieldTypeName);
                        controllerServices.add(service);
                        setMethod = clas.getMethod(String.format("set%s", fieldTypeName), fieldclass);
                    } catch (NoSuchMethodException e) {
                        log4j.info("初始化controller service失败",e);
                    }

                    controller = SysContent.controller.get(controllerName);
                    if(controller!=null){
                        try {
                            setMethod.invoke(controller,service);
                        } catch (IllegalAccessException e) {
                            log4j.info("初始化controller service失败",e);
                        } catch (InvocationTargetException e) {
                            log4j.info("初始化controller service失败",e);
                        }
                    }

                }
            }
            SysContent.controllersService.put(controllerName,controllerServices);
        }
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {

    }
}
